#pragma once
#include <xplatform/XServerClient.h>
#include <xplatform/protobuf/xmsg_com.pb.h>
#include <functional>
namespace google::protobuf::compiler
{
    class Importer;
    class DiskSourceTree;
}
// #include <xplatform/protobuf/xmsg_config.pb.h>
namespace xmsg
{
    class XConfig;
}
class XConfigClient : public XServerClient
{
public:
    static XConfigClient *Get()
    {
        static XConfigClient serverClient;
        return &serverClient;
    }
    //
    bool GetBool(const char *key, bool *ok = nullptr);
    //
    int GetInt(const char *key, bool *ok = nullptr);
    //
    std::string GetString(const char *key);
    // 连接配置中心，开始定时器获取配置
    bool StartGetConfig(const char *server_ip, int server_port,
                        const char *local_ip, int local_port,
                        google::protobuf::Message *conf_mes, int timeout_sec = 10);
    // 定时器回调，这里用来定时调用LoadConfig来获取配置
    void timerCB() override;

    static void Wait();

    static void RegMsgCallback()
    {
        RegCB(xmsg::MSG_SAVE_CONFIG_RES, (MsgCBFunc)&XConfigClient::SaveConfigResCB);
        RegCB(xmsg::MSG_LOAD_CONFIG_RES, (MsgCBFunc)&XConfigClient::LoadConfigResCB);
        RegCB(xmsg::MSG_DEL_CONFIG_RES, (MsgCBFunc)&XConfigClient::DeleteConfigResCB);
        RegCB(xmsg::MSG_LOAD_ALL_CONFIG_RES, (MsgCBFunc)&XConfigClient::LoadAllConfigResCB);
    }

    xmsg::XConfigList GetAllConfig(int page, int page_count, int timeout_sec = 10);
    // 向配置服务器发送配置信息
    /**
     * 此函数的目的是将配置信息封装到消息中并发送出去
     * @param head 指向配置信息的指针，该配置信息将被发送
     */
    void SaveConfig(xmsg::XConfig *head);
    //
    std::function<void(bool,const std::string&)> SaveConfigResCBFunc;
    
    //
    void DeleteConfig(const char *ip, int port);
    void DeleteConfigResCB(xmsg::XMsgHead*head,XMsg *msg);
    /**
     * @brief 加载配置信息
     *
     * 该函数用于向服务端发送加载配置的请求。它将指定的IP和端口信息
     * 封装到一个xmsg::XConfig对象中，并通过SendMsg函数发送出去。
     *
     * @param ip 微服务的IP地址,可以为空，为空会指定为客户端地址
     * @param port 微服务的端口号
     */
    void LoadConfig(const char *ip, int port);
    /**
     * @brief 通过IP和端口获取已经保存到本地的配置信息
     *
     * 本函数根据给定的IP地址和端口，在配置映射中查找对应的配置信息如果找到，
     * 则将配置信息复制到输出参数out_config中如果out_config为空指针，则记录日志信息
     *
     * @param ip 服务器的IP地址，用于标识和查找配置信息
     * @param port 服务器的端口，与IP地址一起唯一标识配置信息
     * @param out_config 输出参数，用于接收找到的配置信息如果为nullptr，则不接收
     * @return true 如果找到配置信息则返回true，否则返回false
     */
    bool GetConfig(const char *ip, int port, xmsg::XConfig *out_config);
    // 配置当前配置的对象
    void SetCurrentServiceConf(google::protobuf::Message *conf)
    {
        std::unique_lock<std::mutex> lock(current_service_conf_mutex_);
        current_service_conf_ = conf;
    }
    /////////////////////////////////////////////////////////////////////
    //// 载入proto文件 线程不安全
    ///@para filename 文件路径
    ///@para class_name 配置的类型
    google::protobuf::Message * LoadPoto(const std::string &poto_path,std::string class_name,std::string &out_proto_code);
private:
    /**
     * @brief 处理保存配置的响应消息，自动调用
     */
    void SaveConfigResCB(xmsg::XMsgHead *head, XMsg *msg);
    /*
     * @brief 处理加载配置的响应消息，自动调用，会把数据保存到本地
     * @param head 消息头，包含配置信息的描述信息
     * @param msg 消息体，包含配置信息的具体数据
     * @return void
     */
    void LoadConfigResCB(xmsg::XMsgHead *head, XMsg *msg); // void(XMsgEvent::*MsgCBFunc)(xmsg::XMsgHead*head,XMsg *msg)
    void LoadAllConfigResCB(xmsg::XMsgHead *head, XMsg *msg);
private:
    XConfigClient(/* args */);
    ~XConfigClient();
    char local_ip_[16] = {0};
    int local_port_ = 0;
    google::protobuf::compiler::Importer *importer_ = nullptr;
    google::protobuf::compiler::DiskSourceTree *source_tree_ = nullptr;
    //根据proto文件动态创建的的message
    google::protobuf::Message *message_ = 0;

    google::protobuf::Message *current_service_conf_ = nullptr;
    std::mutex current_service_conf_mutex_;
};
